# Copyright 2008 Google Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# This file has been modified to run the Treasure-Maps Application written by Thea Ganoe, October 2009.
# Treasure-Maps Copyright 2009, Thea Ganoe. This program is distributed under the terms of the GNU General Public License

import os
import logging
import cgi
import math
import re
from google.appengine.api import users
from google.appengine.ext import db
from google.appengine.ext import webapp
from google.appengine.ext.webapp import template
from google.appengine.ext.webapp import util

import gdata.photos.service
import gdata.media
import gdata.geo
import xml.parsers.expat

from google.appengine.ext.db import djangoforms
import django
from django import http
from django import shortcuts
from django import newforms as forms
from django.shortcuts import render_to_response
from django.http import HttpResponse, HttpResponseRedirect

from django.utils import simplejson
from google.appengine.api import urlfetch 
from xml.dom.minidom import parse, parseString

import models
import bforms
import string

import wsgiref.handlers
import gdata.service
import gdata.urlfetch
import gdata.geo
import datetime


gdata.service.http_request_handler = gdata.urlfetch


def respond(request, user, template, params=None):
  """Helper to render a response, passing standard stuff to the response.

  Args:
    request: The request object.
    user: The User object representing the current user; or None if nobody
      is logged in.
    template: The template name; '.html' is appended automatically.
    params: A dict giving the template parameters; modified in-place.

  Returns:
    Whatever render_to_response(template, params) returns.

  Raises:
    Whatever render_to_response(template, params) raises.
  """
  if params is None:
    params = {}
  if user:
    userArray =  str( user ).split('@')
    params['user'] = userArray[0]
    params['sign_out'] = users.CreateLogoutURL('/')
    params['is_admin'] = (users.IsCurrentUserAdmin() and
                          'Dev' in os.getenv('SERVER_SOFTWARE'))
  else:
    params['sign_in'] = users.CreateLoginURL(request.path)
  if not template.endswith('.html'):
    template += '.html'
  return shortcuts.render_to_response(template, params)

def strip_tags(value):
  "Return the given HTML with all tags stripped."
  return re.sub(r'<[^>]*?>', '', value)

def intro(request):
  user = users.get_current_user()
  if request.method == 'GET':
    statelist = ['All']
    typelist = ['All']
    orgslist = ['All']
    locaslist = ['All']
    routes = db.GqlQuery("SELECT * FROM Route" )
    """routes = db.GqlQuery("SELECT * FROM Route WHERE author = :1","Thea Ganoe")"""
    numroutes = routes.count()
    """Next sections prepare data for the search box forms """
    for route in routes: 
      statelist.append(route.state)
      typelist.append(route.typeTrail)
      orgslist.append(route.organization)
      locaslist.append(route.locationName) 
    """this next trick removes duplicate values! """
    statelist = list(set(statelist))
    typelist = list(set(typelist))
    orgslist = list(set(orgslist))
    locaslist = list(set(locaslist))
    return respond(request, user, 'intro', {'routes' : routes, 'numroutes' : numroutes, 'states' : statelist, 'types' : typelist, 'orcas' : orgslist, 'locas' : locaslist })
  if request.method == 'POST':
    """AJAX call, use post when filtering with the search box form """
    """we have sent var body ="states=" + states + "&types=" + types + "&orcas=" + orcas + "&locas=" + locas;"""
    post= request.POST.copy()  # to make it mutable
    statefilter = post['states']
    typefilter = post['types']
    orcsfilter = post['orcas']
    locasfilter = post['locas']
    statefilter = statefilter.strip()
    typefilter = typefilter.strip() 
    orcsfilter = orcsfilter.strip()
    locasfilter = locasfilter.strip()
    # The Query interface prepares a query using instance methods.
    q = db.Query(models.Route)
    """q =  models.Route.all()"""
    if statefilter != 'All':
      q.filter('state = ',statefilter)
    if typefilter != 'All':
      q.filter('typeTrail = ',typefilter)
    if orcsfilter != 'All':
      q.filter('organization = ',orcsfilter)
    if locasfilter != 'All':
      q.filter('locationName = ',locasfilter)
    # The query is not executed until results are accessed.
    routes = q.fetch(25)
    numroutes = q.count()
    statelist = ['All']
    typelist = ['All']
    orgslist = ['All']
    locaslist = ['All']
    for route in routes: 
      statelist.append(route.state)
      typelist.append(route.typeTrail)
      orgslist.append(route.organization)
      locaslist.append(route.locationName) 
    """this next trick removes duplicate values! """
    statelist = list(set(statelist))
    typelist = list(set(typelist))
    orgslist = list(set(orgslist))
    locaslist = list(set(locaslist))
    return respond(request, user, 'introRoutes', {'routes' : routes, 'numroutes' : numroutes, 'statefilter':statefilter, 'states' : statelist, 'types' : typelist, 'orcas' : orgslist, 'locas' : locaslist })

def renderhtml(request):
  req=urlfetch.fetch('http://www.picasaweb.google.com')
  response= HttpResponse()
  response.write(req.content)
  return response  


def play(request, route_key):
  """MUST have a route selected"""
  """runs the slideshow. The difference between play and aplay are the templates they return"""
  user = users.get_current_user()
  route = models.Route.get(route_key)
  null = ''
  newStr = route.way
  #json_obj = eval(newStr)
  commentStr = route.comments
  if commentStr  == '':
      comments_obj = None
  else:
      comments_obj = eval(commentStr)
  linkList = route.leftLinks
  if linkList  == '':
      linkList_obj = None
  else:
      linkList_obj = eval(linkList)
  gpxString  = smart_str( route.gpx )
  pathList = []
  polyPts = {'encoded_points':'', 'encoded_levels':''}
  encodedObj = ''
  if gpxString:
    gpxString = gpxString.lstrip()
    from xml.dom.minidom import parseString
    dom = parseString(gpxString)
    for node in dom.getElementsByTagName('trkpt'):  # visit every node <bar />
      pathDic = { 'lat': float(node.getAttribute('lat')), 'lng': float( node.getAttribute('lon')) }
      pathList.append(pathDic)
      # @points: [{'lat':100, 'lng':50}, {'lat':102, 'lng':49.8}]
    polyPts = encodePolyPts(pathList)
    if pathList == []:
      for node in dom.getElementsByTagName('rtept'):  # visit every node <bar />
        pathDic = { 'lat': float(node.getAttribute('lat')), 'lng': float( node.getAttribute('lon')) }
        pathList.append(pathDic)
        # @points: [{'lat':100, 'lng':50}, {'lat':102, 'lng':49.8}]
        polyPts = encodePolyPts(pathList)
    encodedObj  = simplejson.dumps(polyPts)
  return respond(request, user, 'viewer', {'ways':newStr, 'comments':comments_obj, 'leftLinks':linkList_obj, 'route':route, 'enc':encodedObj })

 # Encode a signed number into the google maps polyline encode format.
# from:  http://wiki.urban.cens.ucla.edu
def encodeSignedNumber(num):
  sgn_num = num << 1
  if num < 0:
    sgn_num = ~(sgn_num)
  return encodeNumber(sgn_num)

 # Encode an unsigned number in the encode format.
# from:  http://wiki.urban.cens.ucla.edu
def encodeNumber(num):
  encodeString = ""
  while num >= 0x20:
    encodeString += chr((0x20 | (num & 0x1f)) + 63)
    num >>= 5
  encodeString += chr(num + 63)
  return encodeString

# Create the encoded polyline and level strings.
 # @points: [{'lat':100, 'lng':50}, {'lat':102, 'lng':49.8}]
 #   This function takes a list of dictionaries (each dictionary contains a
 #   single 'lat','lng' pair) and returns a dictionary: 
 #     {'encoded_points': string, 'encoded_levels': string}.
# from:  http://wiki.urban.cens.ucla.edu
def encodePolyPts(points):
  i = 0
  plat = 0
  plng = 0
  encoded_points = ""
  encoded_levels = ""
  for i in range(0, len(points)):
    point = points[i]
    lat = point['lat']
    lng = point['lng']
    level = 3 - i%4                    
    late5 = int(math.floor(lat * 1e5))
    lnge5 = int(math.floor(lng * 1e5)) 
    dlat = late5 - plat
    dlng = lnge5 - plng                
    plat = late5
    plng = lnge5                       

    encoded_points += encodeSignedNumber(dlat) + encodeSignedNumber(dlng)
    encoded_levels += encodeNumber(level) 

  return {'encoded_points': encoded_points, 'encoded_levels': encoded_levels}


def mapShow(request, route_key):
  """creates a static google map of the entire route """
  #http://maps.google.com/maps/api/staticmap?size=400x400&path=weight:3|color:orange|enc:polyline_data
  user = users.get_current_user()
  route = models.Route.get(route_key)
  pathList = []
  newStr = route.way
  #'{"description":"'+ route.routeName +'", "img":"'+route.img+'", "getPic": "' + route.img +'", "zoom":"'+ zoomstring +'" ,  "longitude":"'+ route.longitude +'", "latitude":"'+ route.latitude +'", "position": "0",  "heading": "" }'
  ways_obj = simplejson.loads(newStr)
  sizeofWay = len(ways_obj['way'])
  for way in ways_obj['way']:
    pathDic = { 'lat': float(way['latitude']), 'lng': float( way['longitude']) }
    #pathString = pathString + '|' + str(way['latitude']) + ',' +  str( way['longitude'])
    pathList.append(pathDic)
    # @points: [{'lat':100, 'lng':50}, {'lat':102, 'lng':49.8}]
  polyPts = encodePolyPts(pathList)
  return respond(request, user, 'staticMap', {'enc':polyPts  } )

def aplay(request, route_key):
  """MUST have a route selected"""
  """runs the slideshow. This one is for use with AJAX callback functions"""
  user = users.get_current_user()
  route = models.Route.get(route_key)
  null = ''
  newStr = route.way
  json_obj = eval(newStr)
  commentStr = route.comments
  if commentStr  == '':
      comments_obj = None
  else:
      comments_obj = eval(commentStr)
  linkList = route.leftLinks
  if linkList  == '':
      linkList_obj = None
  else:
      linkList_obj = eval(linkList)
  gpxString  = smart_str( route.gpx )
  pathList = []
  polyPts = {'encoded_points':'', 'encoded_levels':''}
  encodedObj = ''
  if gpxString:
    gpxString = gpxString.lstrip()
    from xml.dom.minidom import parseString
    dom = parseString(gpxString)
    for node in dom.getElementsByTagName('trkpt'):  # visit every node <bar />
      pathDic = { 'lat': float(node.getAttribute('lat')), 'lng': float( node.getAttribute('lon')) }
      pathList.append(pathDic)
      # @points: [{'lat':100, 'lng':50}, {'lat':102, 'lng':49.8}]
    polyPts = encodePolyPts(pathList)
    if pathList == []:
      for node in dom.getElementsByTagName('rtept'):  # visit every node <bar />
        pathDic = { 'lat': float(node.getAttribute('lat')), 'lng': float( node.getAttribute('lon')) }
        pathList.append(pathDic)
        # @points: [{'lat':100, 'lng':50}, {'lat':102, 'lng':49.8}]
        polyPts = encodePolyPts(pathList)
    encodedObj  = simplejson.dumps(polyPts)
  return respond(request, user, 'aviewer', {'ways':newStr, 'comments':comments_obj, 'leftLinks':linkList_obj, 'route':route, 'enc':encodedObj })

def addComment(request, route_key):
  user = users.get_current_user()
  if user is None:
    return http.HttpResponseForbidden('You must be signed in to add or edit a route')
  if request.method == 'POST':
    route = models.Route.get(route_key)
    """use post when updating a route form """
    #'{"comments":[]}'
    newString = post['cmtbx']
    commentStr = route.comments
    if commentStr == '':
      comments_obj ='{"comments":[]}'
    comments_obj = simplejson.loads(commentStr)
    now = str(datetime.datetime.now())
    username = user.nickname()
    #this part will delete previous comments by same user
    for cmt in comments_obj['comments']:
      if cmt['user'] == username:
	comments_obj['comments'].remove(cmt)
    comments_obj['comments'].append( { 'comment':newString, 'user':username,  'date':now })
    comments = simplejson.dumps(comments_obj, ensure_ascii=False)
    comments = comments.encode('ascii')
    route.comments = comments
    db.put(route)
    newStr = route.way
    null = ''
    json_obj = eval(newStr)
    linkList = route.leftLinks
    if linkList  == '':
      linkList_obj = None
    else:
      linkList_obj = eval(linkList)
    return respond(request, user, 'viewer', {'ways':json_obj, 'comments':comments_obj, 'route':route})

def newComment(request, route_key):
  user = users.get_current_user()
  if user is None:
    return http.HttpResponseForbidden('You must be signed in to add or edit a route')
  post = request.POST.copy()  # to make it mutable
  route = models.Route.get(route_key)
  """use post when updating a route form """
  #'{"comments":[]}'
  newString =  post['cmtbx']
  commentStr = route.comments
  if commentStr == '':
    comments_obj ='{"comments":[]}'
  comments_obj = simplejson.loads(commentStr)
  now = str(datetime.datetime.now())
  #by theaellen@hotmail.com on 2009-09-22 16:53:46.129564 
  username = user.nickname()
  parts = username.split('@')
  shortname = parts.pop(0)
  #this part will delete previous comments by same user
  for cmt in comments_obj['comments']:
    if cmt['user'] == username:
      comments_obj['comments'].remove(cmt)
  comments_obj['comments'].append( { 'comment':newString, 'user':username,  'date':now, 'shortname':shortname})
  comments = simplejson.dumps(comments_obj, ensure_ascii=False)
  comments = comments.encode('ascii')
  route.comments = comments
  db.put(route)
  newStr = route.way
  null = ''
  json_obj = eval(newStr)
  linkList = route.leftLinks
  if linkList  == '':
    linkList_obj = None
  else:
    linkList_obj = eval(linkList)
  return respond(request, user, 'commentList', {'comments':comments_obj } )

def addLeftLink(request, route_key):
  user = users.get_current_user()
  if user is None:
    return http.HttpResponseForbidden('You must be signed in to add or edit a route')
  if request.method == 'POST':
    route = models.Route.get(route_key)
    """use post when updating a route form """
    newString = cgi.escape(request.POST['leftLinksURL'])
    anewString = cgi.escape(request.POST['leftLinksTITLE'])
    leftLinksStr = route.leftLinks
    if leftLinksStr == '':
      links = []
      leftLinks_obj = [links]
    leftLinks_obj = simplejson.loads(leftLinksStr)
    leftLinks_obj.append( {'urlLink':newString, 'titleLink':anewString })
    leftLinks = simplejson.dumps(leftLinks_obj, ensure_ascii=False)
    leftLinks = leftLinks.encode('ascii')
    route.leftLinks = leftLinks
    db.put(route)
    routes = db.GqlQuery("SELECT * FROM Route ")
    return respond(request, user, 'routeList', {'routes' : routes })

def routeList(request):
  user = users.get_current_user()
  if user is None:
    return http.HttpResponseForbidden('You must be signed in to add or edit a route')
  routes = db.GqlQuery("SELECT * FROM Route WHERE owner = :1", user)
  """routes = db.GqlQuery('SELECT * FROM Route ORDER BY routeName ASC')"""
  return respond(request, user, 'routeList', {'routes' : routes })

def routeDelete(request, route_key):
  user = users.GetCurrentUser()
  if user is None:
    return http.HttpResponseForbidden('You must be signed in to add or edit a route')
  entity = db.get(route_key)
  entity.delete()
  routes = db.GqlQuery("SELECT * FROM Route WHERE owner = :1", user)
  return respond(request, user, 'routeList', {'routes' : routes })

def editRoute(request, route_key):
  """Edit a route.  Modifies ways object for only way[0] """ 
  user = users.get_current_user()
  if user is None:
    return http.HttpResponseForbidden('You must be signed in to add or edit a route')
  if request.method == 'GET':
    route =  db.get(route_key)
    routeform = bforms.RouteForm(instance=route)
    return respond(request, user, 'routeNew', { 'route':route, 'routeform':routeform })
  if request.method == 'POST':
    user = users.GetCurrentUser()
    if user is None:
      return http.HttpResponseForbidden('You must be signed in to add or edit a route')
    route =  db.get(route_key)
    form = bforms.RouteForm(request.POST)
    if form.is_valid():
      tmpStringr = form.clean_data['routeName'] 
      route.routeName = cgi.escape(tmpStringr)
      tmpStringa = form.clean_data['author'] 
      route.author = cgi.escape(tmpStringa)
      tmpStringla =  form.clean_data['latitude']
      route.latitude = cgi.escape(tmpStringla)
      tmpStringlo = form.clean_data['longitude']
      route.longitude = cgi.escape(tmpStringlo)
      zoomstring = form.clean_data['zoom']
      route.zoom = zoomstring
      zoomstring = str(zoomstring)
      tmpStringn = form.clean_data['state']
      route.state = cgi.escape(tmpStringn)
      tmpStringn = form.clean_data['locationName']
      route.locationName = cgi.escape(tmpStringn)
      tmpStringn = form.clean_data['typeTrail']
      route.typeTrail = cgi.escape(tmpStringn)
      tmpStringn = form.clean_data['organization']
      route.organization = cgi.escape(tmpStringn)
      tmpStringo = form.clean_data['intro']
      route.intro = cgi.escape(tmpStringo)
      tmpStringi = form.clean_data['img']
      route.img = tmpStringi
      """this part gets ugly because we have object inside object to edit """
      tempway =  '{"description":"'+ route.routeName +'", "img":"'+route.img+'", "getPic": "' + route.img +'", "zoom":"'+ zoomstring +'" ,  "longitude":"'+ route.longitude +'", "latitude":"'+ route.latitude +'", "position": "0",  "heading": "" }'
      tempway_obj = simplejson.loads(tempway)
      newStr = route.way
      newway_obj = simplejson.loads(newStr)
      newway_obj['way'][0] = tempway_obj
      ways = simplejson.dumps(newway_obj, ensure_ascii=False)
      ways = ways.encode('ascii')
      route.way = ways
      db.put(route)
      routes = db.GqlQuery('SELECT * FROM Route ORDER BY routeName ASC')
      return respond(request, user, 'routeList', {'routes' : routes })

def newRoute(request):
  """Make a new route""" 
  user = users.get_current_user()
  if user is None:
    return http.HttpResponseForbidden('You must be signed in to add or edit a route')
  if request.method == 'GET':
    route = models.Route(routeName='new', owner=user, state='USA', typeTrail='other', parking='[]', restrooms='[]', leftLinks='[]', gpx = '', comments='')
    routeform = bforms.RouteForm(instance=route)
    return respond(request, user, 'routeNew', { 'route':route, 'routeform':routeform })
  if request.method == 'POST':
    #create a new route to db.put in database for first time (different from editing above)
    form = bforms.RouteForm(request.POST)
    if form.is_valid():
      tmpStringr = form.clean_data['routeName'] 
      routeName = cgi.escape(tmpStringr)
      tmpStringa = form.clean_data['author'] 
      author = cgi.escape(tmpStringa)
      tmpStringla =  form.clean_data['latitude']
      latitude = cgi.escape(tmpStringla)
      tmpStringlo = form.clean_data['longitude']
      longitude = cgi.escape(tmpStringlo)
      zoom = form.clean_data['zoom']
      zoomstring = str(zoom)
      tmpStringn = form.clean_data['state']
      state = cgi.escape(tmpStringn)
      tmpStringn = form.clean_data['locationName']
      locationName = cgi.escape(tmpStringn)
      tmpStringn = form.clean_data['typeTrail']
      typeTrail = cgi.escape(tmpStringn)
      tmpStringn = form.clean_data['organization']
      organization = cgi.escape(tmpStringn)
      tmpStringo = form.clean_data['intro']
      intro = cgi.escape(tmpStringo)
      tmpStringi = form.clean_data['img']
      img = cgi.escape(tmpStringi)
      parking = '[]'
      restrooms = '[]'
      leftLinks = '[]'
      #adds a way that looks like the route header at position 0
      way = '{"way":[ {"description":"Title :'+routeName+'", "img":"'+img+'", "getPic": "' + img +'", "zoom":"'+ zoomstring +'" ,  "longitude":"'+ str(longitude) +'", "latitude":"'+ str(latitude) +'", "position": "0",  "heading": "" } ]}'
      gpx = ''
      route = models.Route(routeName = routeName, author = author, owner = user, latitude=latitude, longitude = longitude, zoom = zoom, state=state, locationName = locationName, typeTrail = typeTrail, organization = organization, intro=intro, parking=parking, restrooms=restrooms, leftLinks=leftLinks, comments='{"comments":[]}', way=way, gpx=gpx )
      db.put(route)
      routes = db.GqlQuery('SELECT * FROM Route ORDER BY routeName ASC')
      return respond(request, user, 'routeList', {'routes' : routes })

def routeDetails(request, route_key):
  """MUST have a route selected"""
  """Edits an existing route.  GET displays a form, POST processes changes made"""
  user = users.get_current_user()
  if user is None:
    return http.HttpResponseForbidden('You must be signed in to add or edit a route')
  if request.method == 'GET':
    """ use GET when displaying an existing route  """
    route =  db.get(route_key)
    newStr = route.way
    if newStr == None:
      newStr = '{"way":[]}'
    json_obj = simplejson.loads(newStr)
    newStr = newStr.encode('ascii')
    #gpxString  = smart_str( route.gpx )
    gpxString = route.gpx
    pathList = []
    polyPts = {'encoded_points':'', 'encoded_levels':''}
    encodedObj = ''
    if gpxString:
      from xml.dom.minidom import parseString
      try:
        dom = xml.dom.minidom.parseString(gpxString) 
      except Exception:
        gString = "Invalid XML"
      else:
        for node in dom.getElementsByTagName('trkpt'):  # visit every node <bar />
          pathDic = { 'lat': float(node.getAttribute('lat')), 'lng': float( node.getAttribute('lon')) }
          pathList.append(pathDic)
          # @points: [{'lat':100, 'lng':50}, {'lat':102, 'lng':49.8}]
        polyPts = encodePolyPts(pathList)
        if pathList == []:
          for node in dom.getElementsByTagName('rtept'):  # visit every node <bar />
            pathDic = { 'lat': float(node.getAttribute('lat')), 'lng': float( node.getAttribute('lon')) }
            pathList.append(pathDic)
            # @points: [{'lat':100, 'lng':50}, {'lat':102, 'lng':49.8}]
            polyPts = encodePolyPts(pathList)
    encodedObj  = simplejson.dumps(polyPts)
    routeform = bforms.RouteForm(instance=route)
    return respond(request, user, 'routeDetails', { 'route':route, 'routeform':routeform, 'ways':json_obj['way'], 'gpxString':gpxString, 'enc':encodedObj })
  if request.method == 'POST':
    """use post when updating  forms.  Can be frmRouteData, formGPXData, or form uploadGPX """
    post= request.POST.copy()  # to make it mutable
    route =  db.get(route_key)
    try:
      temp = request.POST['JSONbox']
      route.way = cgi.escape(temp);
      db.put(route)
    except Exception:
      fileData = request.FILES['subGPX']
      gpxString = fileData['content']
      gpxString = gpxString.lstrip()
      #gpxString = cgi.escape(gpxString)
      #route.gpx = unicode(gpxString, "UTF-8")
      #route_key = request.POST['frmKey']
      route.gpx = gpxString
      db.put(route)
    newStr = route.way
    if newStr == None:
      newStr = '{"way":[]}'
    json_obj = simplejson.loads(newStr)
    newStr = newStr.encode('ascii')
    #gpxString  = smart_str( route.gpx )
    #gpxString = route.gpx
    pathList = []
    polyPts = {'encoded_points':'', 'encoded_levels':''}
    encodedObj = ''
    if gpxString:
      from xml.dom.minidom import parseString
      try:
        dom = xml.dom.minidom.parseString(gpxString) 
      except Exception:
        gString = "Invalid XML"
      else:
        for node in dom.getElementsByTagName('trkpt'):  # visit every node <bar />
          pathDic = { 'lat': float(node.getAttribute('lat')), 'lng': float( node.getAttribute('lon')) }
          pathList.append(pathDic)
          # @points: [{'lat':100, 'lng':50}, {'lat':102, 'lng':49.8}]
        polyPts = encodePolyPts(pathList)
        if pathList == []:
          for node in dom.getElementsByTagName('rtept'):  # visit every node <bar />
            pathDic = { 'lat': float(node.getAttribute('lat')), 'lng': float( node.getAttribute('lon')) }
            pathList.append(pathDic)
            # @points: [{'lat':100, 'lng':50}, {'lat':102, 'lng':49.8}]
            polyPts = encodePolyPts(pathList)
    encodedObj  = simplejson.dumps(polyPts)
    routeform = bforms.RouteForm(instance=route)
    return respond(request, user, 'routeDetails', { 'route':route, 'routeform':routeform, 'ways':json_obj['way'], 'gpxString':gpxString, 'enc':encodedObj })

def smart_str(s, encoding='utf-8', strings_only=False, errors='strict'):
  """
  Returns a bytestring version of 's', encoded as specified in 'encoding'.
  If strings_only is True, don't convert (some) non-string-like objects.
  """
  if s is None:
    return s
  if strings_only and isinstance(s, (types.NoneType, int)):
    return s
  if isinstance(s, str):
    try:
      return unicode(s).encode(encoding, errors)
    except UnicodeDecodeError:
      return s
  elif not isinstance(s, basestring):
    try:
      return str(s)
    except UnicodeEncodeError:
      if isinstance(s, Exception):
        # An Exception subclass containing non-ASCII data that doesn't
        # know how to print itself properly. We shouldn't raise a
        # further exception.
        return ' '.join([smart_str(arg, encoding, strings_only,
                    errors) for arg in s])
      return unicode(s).encode(encoding, errors)
  elif isinstance(s, unicode):
    return s.encode(encoding, errors)
  elif s and encoding != 'utf-8':
    return s.decode('utf-8', errors).encode(encoding, errors)
  else:
    return s

def routeDetailsGPX(request, route_key):
  """adds the GPX directly from the input box"""
  """POST  updates the route and page """
  user = users.get_current_user()
  if user is None:
    return http.HttpResponseForbidden('You must be signed in to add or edit a route')
  if request.method == 'POST':
    """use post when entering a new GPX"""
    route =  db.get(route_key)
    gpxString =  request.POST['GPXbox']
    # this encoding stores as XML format in the db field
    #gpxString = gpxString.encode('ISO-8859-1')
    #gpxString = gpxString.encode('UTF-8')
    #gpxString = smart_str(gpxString)
    gpxString = gpxString.lstrip()
    #gpxString = cgi.escape(gpxString)
    #route.gpx = unicode(gpxString, "UTF-8")
    route.gpx = gpxString
    db.put(route)
    routes = db.GqlQuery('SELECT * FROM Route ORDER BY routeName ASC')
    return respond(request, user, 'routeList', {  'routes' : routes })

def getPics(request):
  """Takes a feed from a Picasa album and shows all the pics."""
  #req.open('GET', '/rpcGetPics?handlename='+ newHandle + "&albumname=" + newAlbum, true);
  user = users.get_current_user()
  if user is None:
    return http.HttpResponseForbidden('You must be signed in to add or edit a route')
  gd_client = gdata.photos.service.PhotosService()
  tmpStringh =  request.GET['handlename']
  handle = cgi.escape(tmpStringh);
  tmpStringa = request.GET['albumname']
  album_name= cgi.escape(tmpStringa);
  picset = []
  feed = gd_client.GetFeed('/data/feed/api/user/%s/album/%s?kind=photo' % (handle, album_name))
  # to avoid a null value for the geopoint:
  for entry in feed.entry:
    if entry.geo.Point:
      pos = entry.geo.Point.pos.text
    else:
      pos = '0 0'
    picsrc = entry.content.src
    description =  str(entry.summary.text )
    description = description.replace("'", "-")
    description = description.replace('"', "_")
    picLink = entry.link[1].href
    picset.append( { 'picsrc':picsrc, 'pos':pos,  'description':description, 'getPic':picLink })
    #feed: {'getPic': 'http://picasaweb.google.com/lh/photo/bSBe4H_x46ccRSQz6oxlrA', 'picsrc': 'http://lh6.ggpht.com/rambletown/SMhxn3BS7oI/AAAAAAAAAig/1Im3lGZ8rG4/HPIM2604.JPG', 'pos': '35.9904424 -78.9063164', 'description': 'Corner of Blackwell St and S Service Rd W, looking south'}
  return respond(request, user, 'picpics', { 'feed': picset} )

def getPicsGPX(request):
  """loads pictures from waypoints in the gpx file"""
  user = users.get_current_user()
  if user is None:
    return http.HttpResponseForbidden('You must be signed in to add or edit a route')
  if request.method == 'POST':
    """use post when entering a new GPX"""
    post = request.POST.copy()  # to make it mutable
    route_key=post['route_key']
    route =  db.get(route_key)
    gpx_obj = ''
    gList = []
    imgsrc = 'test.jpg'
    #gpxString  = smart_str( route.gpx )
    gpxString = route.gpx
    if gpxString:
      gpxString = gpxString.lstrip()
      from xml.dom.minidom import parseString
      dom = parseString(gpxString)
      waypoint=dom.getElementsByTagName('wpt')
      for node in waypoint:
        xlat=node.attributes["lat"]
        xlon=node.attributes["lon"]
        pos = xlat.value + ' ' + xlon.value
        desc =  (node.getElementsByTagName('desc')[0]).toxml()
        description = strip_tags(desc)
        lnk = node.getElementsByTagName('link')
        imgsrc = ''
        typeLink = ''
        imgsrc = ''
        for lk in lnk:
          imgsrc = lk.attributes["href"].value
          if imgsrc != '':
            typenode = node.getElementsByTagName('type')
            typeLink = typenode[0].toxml()
        gList.append( { 'picsrc':imgsrc, 'pos':pos, 'description':description, 'typeLink':typeLink, 'getPic':imgsrc } )
	#gJson = simplejson.dumps(gList)
    return respond(request, user, 'gpxpics', { 'gpxPoints':gList } )

def getAlbum(request):
  """AJAX XHR to input Picasa handle."""
  #builds:  req.open('GET', '/rpcGetHandle?handlename='+ newPos, true);
  user = users.get_current_user()
  if user is None:
    return http.HttpResponseForbidden('You must be signed in to add or edit a route')
  tempStringh = request.GET['handlename']
  handle = cgi.escape(tempStringh)
  gd_client = gdata.photos.service.PhotosService()
  try:
    afeed = gd_client.GetUserFeed(user=handle)
  except:
    response= HttpResponse()
    response.write('unknown username')
    return response
  return respond(request, user, 'album', {'feed': afeed} )


def savePics(request):
  """The pictures are added to routes in the javascript.  at this point we want to display the new route status """
  #from javascript var body = "route_key=" + key + "&cbx=" + getstr ;
  user = users.get_current_user()
  if user is None:
    return http.HttpResponseForbidden('You must be signed in to add or edit a route')
  post= request.POST.copy()  # to make it mutable
  route_key = post['route_key']
  route =  db.get(route_key)
  newStr = route.way
  """pylist is a python list of strings from the checked checkboxes"""
  try:
    pylist = eval(post['cbx'])
  except:
    return render_to_response('error.html', {'getstr':post['cbx'] } )
  else:
    json_obj = simplejson.loads(newStr)
    #next step adds new pic nodes at the lists bottom end of the existing nodes
    position = len(json_obj['way'])
    for py in pylist:
      """add to bottom of way list"""
      #  {'picsrc': 'http:.../HPIM2015.JPG', 'pos': '44.9408734 -93.097608', 'description': 'Saint Paul, Minnesota'} 
      # "{ picsrc:'', pos:'35.7729492 -82.995903', description:'Brown Gap. 3 gravel roads converged', typeLink:'', getPic:''}"
      newWay = {}
      """split the values out of the string"""
      try:
        py_obj = eval(py)
      except:
        thisError = sys.exc_info()[0]
        return render_to_response('error.html', {'getstr':py, 'thisError':thisError } )
      else:
        #there is a problem with XMLHttpRequest when a value is "None", so it must be set to ""
        description = py_obj['description']
        if description== None : description = ""
        description = cgi.escape(description)
        img = py_obj['picsrc']
        if img == None : img = ""
        getPic = py_obj['getPic'] 
        if getPic == None : getPic = ""
        longitude = ""
        latitude = ""
        ar=  py_obj['pos']
        if ar != None:
          latitude = ar.split()[0]
          longitude = ar.split()[1]
        #note:  getPic is the link used to show the original in the picasa album
        newWay = { 'description':description, 'img':img , 'getPic':getPic, 'zoom':'17', 'longitude':longitude, 'latitude':latitude, 'position': str(position) , 'heading': '0' }
        json_obj['way'].append(newWay)
        position = position + 1
    way = simplejson.dumps(json_obj, ensure_ascii=True)
    way = way.encode('ascii')
    route.way = way
    db.put(route)
    return respond(request, user, 'routeWays', { 'ways':json_obj['way']  }  )

def reway(request):
  #builds:  ways using req.open('GET', '/zrpc?ways='+ way_json, true);
  #ways_list = simplejson.loads(request.body)
  #ways_dict = {}
  post = request.POST.copy()  # to make it mutable
  result = post['way']
  ways_list = eval(result)
  #ways_list = simplejson.dumps(result)
  #ways_dict.update(ways_list)
  return render_to_response('routeWays.html', {'ways':ways_list})

def saveway(request):
  #var body = "route_key=" + key + "&coverPic=" + coverPic + "&coverLat=" + coverlat + "&coverLon="+coverlon+ "&way=" + JSON.stringify(myObj);
  #returns html for all nodes 
  post = request.POST.copy()  # to make it mutable
  result = post['way']
  route_key=post['route_key']
  route =  db.get(route_key)
  route.latitude = post['coverLat']
  route.longitude = post['coverLon']
  route.img = post['coverPic']
  route.way = result
  db.put(route)
  ways = eval(result)
  return render_to_response('routeWays.html', {'ways':ways['way'] , 'jsonWay': result})



